﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConnectFour
{
    class Ryan : Player
    {
        int maxD = 7;
        int MaxCol;
        static Random r = new Random();
        //Weights for regions on the board
        int[,] IBEF = new int[6, 7] { { 3, 4, 5, 7, 5, 4, 3 }, { 4, 6, 8, 10, 8, 6, 4 }, { 5, 8, 11, 13, 11, 8, 5 }, { 5, 8, 11, 13, 11, 8, 5 }, { 4, 6, 8, 10, 8, 6, 4 }, { 3, 4, 5, 7, 5, 4, 3 } };
        //my opponents color
        Checker opColor;

        public Ryan(Checker myColor, Board board) : base(myColor, board, null) { }

        public override void GameOver(Checker winner) { }

        public override int Move(int lastMove)
        {
            Board myBoard = new Board();
            //determine opponents color
            if (myColor == Checker.Red)
            {
                opColor = Checker.Black;
            }
            else
            {
                opColor = Checker.Red;
            }
            //makes a copy of the second board
            myBoard = restore(myBoard, board);

            //recursive minimax function
            findMove(0, myColor, myBoard);
            //return the best colum
            return MaxCol;
        }

        //recursive mimimax function
        public int findMove(int curDepth, Checker playerToMove, Board myBoard)
        {
            //Board to have changes made to it
            Board WorkBoard = new Board();
            //copy the board passed
            WorkBoard = restore(WorkBoard, myBoard);
            //check for a winning or losing board
            Checker TestCheck = myColor;
            if (myBoard.CheckForWinner(out TestCheck))
            {
                if (TestCheck != Checker.Empty)
                {
                    //if I win return max value - how many moves out
                    if (TestCheck == myColor)
                    {
                        return 255 - curDepth;
                    }
                    //if I lose return lowest value + how many moves out
                    else if (TestCheck == opColor)
                    {
                        return 0 + curDepth;
                    }
                }
            }
            //if you have reached the max depth return the current board value
            if (curDepth == maxD)
            {
                return Value(myColor, opColor, myBoard);
            }
            //if it is my turn
            if (playerToMove == myColor)
            {
                int max = int.MinValue;
                int col = 0;
                //loop for each colum
                for (int i = 0; i < 7; i++)
                {
                    //if it is playable put a piece there
                    if (WorkBoard.Playable(i))
                    {
                        WorkBoard.Play(myColor, i);
                        //Recusive call after this move has been made
                        int val = findMove(curDepth + 1, opColor, WorkBoard);
                        //if new move is better than last best move make it the new best move
                        if (max <= val)
                        {
                            max = val;
                            col = i;
                        }
                        //restore the WorkBoard to the passed board for the next iteration
                        WorkBoard = restore(WorkBoard, myBoard);
                    }
                }
                //set the Global MaxCol to the best move
                MaxCol = col;
                //return the current max value
                return max;
            }
            //if it is not my turn
            else
            {
                int min = int.MaxValue;
                //loop for each colum
                for (int i = 0; i < 7; i++)
                {
                    //if it is playable make the move
                    if (WorkBoard.Playable(i))
                    {
                        WorkBoard.Play(opColor, i);
                        //Recursive call after this move has been made
                        int val = findMove(curDepth + 1, myColor, WorkBoard);
                        //if new value is more minimum than last min make it the new min
                        if (min > val)
                        {
                            min = val;
                        }
                        //Restore the board for the next call
                        WorkBoard = restore(WorkBoard, myBoard);
                    }
                }
                //return the min value
                return min;
            }
        }

        //Copy the board and return it
        Board restore(Board Restoree, Board Restorer)
        {
            Restoree = new Board();
            for (int i = 0; i < 6; i++)
            {
                for (int j = 0; j < 7; j++)
                {
                    if (Restorer[i, j] == Checker.MovingRed)
                    {
                        Restoree.Play(Checker.Red, j);
                    }
                    else if (Restorer[i, j] == Checker.MovingBlack)
                    {
                        Restoree.Play(Checker.Black, j);
                    }
                }
            }
            return Restoree;
        }

        //Determines the value of a given board. Based off the number of winning lines per spot
        int Value(Checker myColor, Checker opColor, Board CheckBoard)
        {
            //base value of the return to avaid negatives
            int baseVal = 128;
            //actual value of the spot
            int sum = 0;
            //loop through the board and add up the score
            for (int i = 0; i < 6; i++)
            {
                for (int j = 0; j < 7; j++)
                {
                    if (CheckBoard[i, j] == (myColor | Checker.Moving) || CheckBoard[i, j] == myColor)
                    {
                        sum += IBEF[i, j];
                    }
                    else if (CheckBoard[i, j] == (opColor | Checker.Moving) || CheckBoard[i, j] == opColor)
                    {
                        sum -= IBEF[i, j];
                    }
                }
            }
            //return the total value of the board
            return baseVal + sum;
        }
    }
}
